/**
 * Copyright 2007-2008. Chongqing First Information & Network Co., Ltd. All
 * rights reserved. <a>http://www.cqfirst.com.cn</a>
 */
package com.cqcis.uip.base.framework.codec;

import java.util.LinkedList;
import java.util.List;

import com.cqcis.uip.base.framework.utils.ByteBuffer;

/**
 * socket接口标准字节流包打包实现.
 * 规范参照与CRM接口打包规范。
 * 
 * @author huangmy
 * @date   2007-12-14
 */
public class StandardObjectDecoderImpl implements ObjectDecoder {
	public final static int PACKET_LENGTH_MAX = 10 * 1024 * 1024;  /*默认包最大长度为10M*/
	private int packetLengthMax = PACKET_LENGTH_MAX;
	private int[] packetHead = new int[]{0x01, 0x02};       /*包头ͷ*/
	private int[] packetTail = new int[]{0xfe, 0xff};       /*包尾*/
	private String sendSysId;       /*发送系统ID*/
	private String recvSysId;       /*接收系统ID*/
	private String password;        /*认证密码*/
	private String encoding = "UTF-8";
	private String wantVerify; 
	
	/**
	 * 校验信息
	 * 
	 * @return
	 */
	private String getWantVerify() {
		if (wantVerify == null) {
			wantVerify = sendSysId + recvSysId + password;
		}
		
		return wantVerify;
	}
	
	/**
	 * 读取完整的socket数据包
	 * @see com.cqcis.uip.base.framework.filters.StandardObjectDecoderImpl
	 */	
	public Object decode(ByteBuffer buffer) throws Exception {		
		if (!buffer.hasRemaining() || buffer.remaining() < 22) {
			return null;
		}
		
		List<String> xmlList = null;
		
		byte[] validateBuf = new byte[12];
		int packetLen;   /*数据包长度*/
		String validateStr = null;
		
		/*校验ͷ*/
		if (   buffer.get() == packetHead[0] 
		    && buffer.get() == packetHead[1]
		    && buffer.get(validateBuf) != null 
		   )
		{	
			int validLength = validateBuf.length; // 有效长度
			for (int i = validateBuf.length - 1; i > 0; i --) {
				if (validateBuf[i] == (byte)0x00) {
					validLength --;
				}
			}
			validateStr = new String(validateBuf,0,validLength);			
			if (!validateStr.equals(getWantVerify())) {
				throw new DataFormatException("Socket packet verify Exception: recv verify = " 
						+ validateStr + ", but want = " + getWantVerify());
			}
			
			buffer.getShort();
			packetLen = buffer.getInt();
			
			if (packetLen > packetLengthMax) {
				throw new DataFormatException("Socket packet length is too long: length = " + packetLen);				
			}
			
			if (packetLen == 0) {
				throw new DataFormatException("Socket packet length is zero: length = " + packetLen);
			}
			
			if (!buffer.hasRemaining() || buffer.remaining() < packetLen + 2) {						
				return null;
			}
			
			byte[] packetBuf = new byte[packetLen];
			
			buffer.get(packetBuf);
			
			if (   buffer.get() == (byte)packetTail[0] 
			    && buffer.get() == (byte)packetTail[1]
			   ){				
				xmlList = doXmlFileDecode(ByteBuffer.wrap(packetBuf));
			}else {                                
				return null;
			}			
		}else {			
			throw new DataFormatException("Socket packet head verify Exception: Please Check File. ");			
		}
				
		return xmlList;
	}
	
	private List<String> doXmlFileDecode(ByteBuffer buffer) throws Exception {				
		List<String> xmlFileList = new LinkedList<String>();
		
		while (buffer.hasRemaining()) {
			byte[] head = new byte[4];
			buffer.get(head);
			
			int length = buffer.getInt();
			
			if (length > packetLengthMax) {
				throw new DataFormatException("Packet length is too long: length = " + length);				
			}
			
			byte[] xmlFile = new byte[length];		
			buffer.get(xmlFile);	
			
			xmlFileList.add(new String(xmlFile, encoding));
			
			buffer.getShort();
		}
		
		return xmlFileList;
	}
	
	/**
	 * 该方法用于定制需要保存的buffer
	 * @param buffer
	 */	
	protected void processSaveBuffer(ByteBuffer buffer) {
		byte[] buf = new byte[12];
		int packetLen;   /*数据包长度*/	
		/*校验ͷ*/
		if (   buffer.get() == packetHead[0] 
		    && buffer.get() == packetHead[1]
		    && buffer.get(buf) != null 
		    && new String(buf).equals(sendSysId + recvSysId + password)		    
		    ) 
		{
			buffer.getShort();
			packetLen = buffer.getInt();
			
			buffer.limit(packetLen + 20);
		}		
	}

	public void setPacketLengthMax(int packetLengthMax) {
		this.packetLengthMax = packetLengthMax;
	}

	public void setSendSysId(String sendSysId) {
		this.sendSysId = sendSysId;
	}

	public void setRecvSysId(String recvSysId) {
		this.recvSysId = recvSysId;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public void setEncoding(String encoding) {
		this.encoding = encoding;
	}
	
}
